{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "<center>\n",
    "<img src=\"https://github.com/Yorko/mlcourse.ai/blob/master/img/ods_stickers.jpg?raw=true\" />\n",
    "<br>\n",
    "\n",
    "<div style=\"font-weight:700;font-size:25px\"> [mlcourse.ai](https://mlcourse.ai) - Open Machine Learning Course </div> \n",
    "\n",
    "<br>\n",
    "Auteurs: [Vitaliy Radchenko](https://www.linkedin.com/in/vitaliyradchenk0/) et [Yury Kashnitsky](https://yorko.github.io). Traduit et édité par [Christina Butsko](https://www.linkedin.com/in/christinabutsko/), [Egor Polusmak](https://www.linkedin.com/in/egor-polusmak/), [Anastasia Manokhina](https://www.linkedin.com/in/anastasiamanokhina/), [Anna Shirshova](http://linkedin.com/in/anna-shirshova-b908458b), [Yuanyuan Pao](https://www.linkedin.com/in/yuanyuanpao/) et [Ousmane Cissé](https://github.com/oussou-dev). Ce matériel est soumis aux termes et conditions de la licence [Creative Commons CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/). L'utilisation gratuite est autorisée à des fins non commerciales."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "# <center> Thème 5. Ensembles et random forest</center>\n",
    "<center> \n",
    "\n",
    "<div style=\"font-weight:700;font-size:20px\"> Partie 2. Random forest (forêts aléatoires) </div>\n",
    "\n",
    "</center>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "toc": true
   },
   "source": [
    "<h1>Sommaire<span class=\"tocSkip\"></span></h1>\n",
    "<div class=\"toc\"><ul class=\"toc-item\"><li><span><a href=\"#1.-Algorithme\" data-toc-modified-id=\"1.-Algorithme-1\">1. Algorithme</a></span></li><li><span><a href=\"#2.-Comparaison-avec-les-arbres-de-décision-et-le--bagging\" data-toc-modified-id=\"2.-Comparaison-avec-les-arbres-de-décision-et-le--bagging-2\">2. Comparaison avec les arbres de décision et le  bagging</a></span></li><li><span><a href=\"#3.-Paramètres\" data-toc-modified-id=\"3.-Paramètres-3\">3. Paramètres</a></span></li><li><span><a href=\"#4.-Variance-et-dé-corrélation\" data-toc-modified-id=\"4.-Variance-et-dé-corrélation-4\">4. Variance et dé-corrélation</a></span></li><li><span><a href=\"#5.-Biais\" data-toc-modified-id=\"5.-Biais-5\">5. Biais</a></span></li><li><span><a href=\"#6.-Arbres-extrêmement-aléatoires\" data-toc-modified-id=\"6.-Arbres-extrêmement-aléatoires-6\">6. Arbres extrêmement aléatoires</a></span></li><li><span><a href=\"#7.-Similitudes-entre-Random-Forest-et-les-k-plus-proches-voisins\" data-toc-modified-id=\"7.-Similitudes-entre-Random-Forest-et-les-k-plus-proches-voisins-7\">7. Similitudes entre Random Forest et les k plus proches voisins</a></span></li><li><span><a href=\"#8.-Transformation-d'un-jeu-de-données-en-une-représentation-de-grande-dimension\" data-toc-modified-id=\"8.-Transformation-d'un-jeu-de-données-en-une-représentation-de-grande-dimension-8\">8. Transformation d'un jeu de données en une représentation de grande dimension</a></span></li><li><span><a href=\"#9.-Avantages-et-inconvénients-des-forêts-aléatoires\" data-toc-modified-id=\"9.-Avantages-et-inconvénients-des-forêts-aléatoires-9\">9. Avantages et inconvénients des forêts aléatoires</a></span></li><li><span><a href=\"#10.-Mission-de-démonstration\" data-toc-modified-id=\"10.-Mission-de-démonstration-10\">10. Mission de démonstration</a></span></li><li><span><a href=\"#11.-Ressources-utiles\" data-toc-modified-id=\"11.-Ressources-utiles-11\">11. Ressources utiles</a></span></li></ul></div>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "Leo Breiman a réussi à appliquer le bootstrapping non seulement dans les statistiques, mais aussi dans l’apprentissage automatique. Avec Adel Cutler, il a étendu et amélioré l'algorithme de forêt aléatoire [proposé par Tin Kam Ho](http://ect.bell-labs.com/who/tkh/publications/papers/odt.pdf). Ils ont combiné la construction d'arbres non corrélés à l'aide de [CART](https://en.wikipedia.org/wiki/Predictive_analytics#Classification_and_regression_trees_.28CART.29), bagging et la (méthode du sous-espace aléatoire) [random subspace method](https://en.wikipedia.org/wiki/Random_subspace_method).\n",
    "\n",
    "Les arbres de décision sont un bon choix pour le classifieur de base dans le bagging, car ils sont assez sophistiqués et permettent d'obtenir une erreur de classification nulle sur n'importe quel échantillon. La méthode du sous-espace aléatoire (random subspace method) réduit la corrélation entre les arbres et évite ainsi le sur-apprentissage. Avec le bagging, les algorithmes de base sont entraînés sur différents sous-ensembles aléatoires des caractéristiques du jeu de donnée d'origine.\n",
    "\n",
    "L'algorithme suivant construit un ensemble de modèles à l'aide de la méthode du sous-espace aléatoire:\n",
    "\n",
    "1. Soit le nombre d'instances égal à $\\large \\ell$ et le nombre de caractéristiques égal à $\\large d$.\n",
    "2. Choisissez $\\large L$ comme nombre de modèles individuels dans l’ensemble.\n",
    "3. Pour chaque modèle $\\large l$, choisissez le nombre de caractéristiques $\\large dl < d$. En règle générale, la même valeur de $\\large dl$ est utilisée pour tous les modèles.\n",
    "4. Pour chaque modèle $\\large l$, créez un ensemble d'apprentissage en sélectionnant des caractéristiques $\\large dl$ de manière aléatoire dans l'ensemble des caractéristiques de $\\large d$.\n",
    "5. Former chaque modèle.\n",
    "6. Appliquez le modèle d'ensemble résultant à une nouvelle instance en combinant les résultats de tous les modèles de $\\large L$. Vous pouvez utiliser le vote à la majorité ou l'agrégation des probabilités postérieures."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "## 1. Algorithme\n",
    "\n",
    "L'algorithme de construction d'une forêt aléatoire d'arbres $\\large N$ se présente comme suit:\n",
    "\n",
    "* Pour chaque $\\large k = 1, \\dots, N$:\n",
    "    * Générez un bootstrap d'échantillon $\\large X_k$.\n",
    "    * Construisez un arbre de décision $\\large b_k$ sur l'exemple $\\large X_k$:\n",
    "    * Choisissez la meilleure caractéristique en fonction des critères donnés. Fractionner l'échantillon par cette caractéristique pour créer un nouveau niveau d'arborescence. Répétez cette procédure jusqu'à la fin de l'échantillon.\n",
    "    * Construire l'arbre jusqu'à ce que l'une de ses feuilles ne contienne plus que des occurrences $\\large n_\\text{min}$ ou jusqu'à ce qu'une certaine profondeur soit atteinte.\n",
    "    * Pour chaque division ou partition, nous sélectionnons d'abord de manière aléatoire $\\large m$ caractéristiques parmi celles d'origine $\\large d$, puis nous recherchons la meilleure partition suivante uniquement parmi le sous-ensemble.\n",
    "         \n",
    "Le classifieur final est défini par:\n",
    "$$\\large a(x) = \\frac{1}{N}\\sum_{k = 1}^N b_k(x)$$\n",
    "\n",
    "Nous utilisons le vote à la majorité pour la classification et la moyenne pour la régression.\n",
    "\n",
    "Pour les problèmes de classification, il est conseillé de définir $\\large m = \\sqrt{d}$. Pour les problèmes de régression, nous prenons généralement $\\large m = \\frac{d}{3}$, où $\\large d$ est le nombre de caractéristiques. Il est recommandé de construire chaque arbre jusqu'à ce que toutes ses feuilles ne contiennent que des exemples $\\large n_\\text{min} = 1$ pour la classification et $\\large n_\\text{min} = 5$ pour la régression.\n",
    "\n",
    "Vous pouvez voir une forêt aléatoire comme un bagging d'arbres de décision avec la modification de la sélection d'un sous-ensemble aléatoire de caractéristiques à chaque partition.\n",
    "\n",
    "## 2. Comparaison avec les arbres de décision et le  bagging"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Disable warnings in Anaconda\n",
    "import warnings\n",
    "\n",
    "import numpy as np\n",
    "\n",
    "warnings.filterwarnings('ignore')\n",
    "\n",
    "%matplotlib inline\n",
    "from matplotlib import pyplot as plt\n",
    "\n",
    "plt.style.use('ggplot')\n",
    "plt.rcParams['figure.figsize'] = 10, 6\n",
    "%config InlineBackend.figure_format = 'retina'\n",
    "\n",
    "import seaborn as sns\n",
    "from sklearn.datasets import make_circles\n",
    "from sklearn.ensemble import (BaggingClassifier, BaggingRegressor,\n",
    "                              RandomForestClassifier, RandomForestRegressor)\n",
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn.tree import DecisionTreeClassifier, DecisionTreeRegressor"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "n_train = 150        \n",
    "n_test = 1000       \n",
    "noise = 0.1\n",
    "\n",
    "# Generate data\n",
    "def f(x):\n",
    "    x = x.ravel()\n",
    "    return np.exp(-x ** 2) + 1.5 * np.exp(-(x - 2) ** 2)\n",
    "\n",
    "def generate(n_samples, noise):\n",
    "    X = np.random.rand(n_samples) * 10 - 5\n",
    "    X = np.sort(X).ravel()\n",
    "    y = np.exp(-X ** 2) + 1.5 * np.exp(-(X - 2) ** 2)\\\n",
    "        + np.random.normal(0.0, noise, n_samples)\n",
    "    X = X.reshape((n_samples, 1))\n",
    "\n",
    "    return X, y\n",
    "\n",
    "X_train, y_train = generate(n_samples=n_train, noise=noise)\n",
    "X_test, y_test = generate(n_samples=n_test, noise=noise)\n",
    "\n",
    "# One decision tree regressor\n",
    "dtree = DecisionTreeRegressor().fit(X_train, y_train)\n",
    "d_predict = dtree.predict(X_test)\n",
    "\n",
    "plt.figure(figsize=(10, 6))\n",
    "plt.plot(X_test, f(X_test), \"b\")\n",
    "plt.scatter(X_train, y_train, c=\"b\", s=20)\n",
    "plt.plot(X_test, d_predict, \"g\", lw=2)\n",
    "plt.xlim([-5, 5])\n",
    "plt.title(\"Decision tree, MSE = %.2f\" \n",
    "          % np.sum((y_test - d_predict) ** 2))\n",
    "\n",
    "# Bagging with a decision tree regressor\n",
    "bdt = BaggingRegressor(DecisionTreeRegressor()).fit(X_train, y_train)\n",
    "bdt_predict = bdt.predict(X_test)\n",
    "\n",
    "plt.figure(figsize=(10, 6))\n",
    "plt.plot(X_test, f(X_test), \"b\")\n",
    "plt.scatter(X_train, y_train, c=\"b\", s=20)\n",
    "plt.plot(X_test, bdt_predict, \"y\", lw=2)\n",
    "plt.xlim([-5, 5])\n",
    "plt.title(\"Bagging for decision trees, MSE = %.2f\" % np.sum((y_test - bdt_predict) ** 2));\n",
    "\n",
    "# Random Forest\n",
    "rf = RandomForestRegressor(n_estimators=10).fit(X_train, y_train)\n",
    "rf_predict = rf.predict(X_test)\n",
    "\n",
    "plt.figure(figsize=(10, 6))\n",
    "plt.plot(X_test, f(X_test), \"b\")\n",
    "plt.scatter(X_train, y_train, c=\"b\", s=20)\n",
    "plt.plot(X_test, rf_predict, \"r\", lw=2)\n",
    "plt.xlim([-5, 5])\n",
    "plt.title(\"Random forest, MSE = %.2f\" % np.sum((y_test - rf_predict) ** 2));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "Comme nous pouvons le voir sur nos graphiques et les valeurs de MSE ci-dessus, une forêt aléatoire de 10 arbres donne un meilleur résultat qu'un arbre de décision unique et est comparable au bagging avec 10 arbres. La principale différence entre les forêts aléatoires et le bagging réside dans le fait que, dans une forêt aléatoire, la meilleure caractéristique pour une partition est sélectionnée dans un sous-ensemble aléatoire des caractéristiques disponibles, tandis que, dans le bagging, toutes les caractéristiques sont prises en compte pour la division suivante.\n",
    "\n",
    "Nous pouvons également examiner les avantages des forêts aléatoires et du bagging dans les problèmes de classification :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "np.random.seed(42)\n",
    "X, y = make_circles(n_samples=500, factor=0.1, noise=0.35, random_state=42)\n",
    "X_train_circles, X_test_circles, y_train_circles, y_test_circles = \\\n",
    "    train_test_split(X, y, test_size=0.2)\n",
    "\n",
    "dtree = DecisionTreeClassifier(random_state=42)\n",
    "dtree.fit(X_train_circles, y_train_circles)\n",
    "\n",
    "x_range = np.linspace(X.min(), X.max(), 100)\n",
    "xx1, xx2 = np.meshgrid(x_range, x_range)\n",
    "y_hat = dtree.predict(np.c_[xx1.ravel(), xx2.ravel()])\n",
    "y_hat = y_hat.reshape(xx1.shape)\n",
    "plt.contourf(xx1, xx2, y_hat, alpha=0.2)\n",
    "plt.scatter(X[:,0], X[:,1], c=y, cmap='viridis', alpha=.7)\n",
    "plt.title(\"Decision tree\")\n",
    "plt.show()\n",
    "\n",
    "b_dtree = BaggingClassifier(DecisionTreeClassifier(), \n",
    "                            n_estimators=300, random_state=42)\n",
    "b_dtree.fit(X_train_circles, y_train_circles)\n",
    "\n",
    "x_range = np.linspace(X.min(), X.max(), 100)\n",
    "xx1, xx2 = np.meshgrid(x_range, x_range)\n",
    "y_hat = b_dtree.predict(np.c_[xx1.ravel(), xx2.ravel()])\n",
    "y_hat = y_hat.reshape(xx1.shape)\n",
    "plt.contourf(xx1, xx2, y_hat, alpha=0.2)\n",
    "plt.scatter(X[:,0], X[:,1], c=y, cmap='viridis', alpha=.7)\n",
    "plt.title(\"Bagging (decision trees)\")\n",
    "plt.show()\n",
    "\n",
    "rf = RandomForestClassifier(n_estimators=300, random_state=42)\n",
    "rf.fit(X_train_circles, y_train_circles)\n",
    "\n",
    "x_range = np.linspace(X.min(), X.max(), 100)\n",
    "xx1, xx2 = np.meshgrid(x_range, x_range)\n",
    "y_hat = rf.predict(np.c_[xx1.ravel(), xx2.ravel()])\n",
    "y_hat = y_hat.reshape(xx1.shape)\n",
    "plt.contourf(xx1, xx2, y_hat, alpha=0.2)\n",
    "plt.scatter(X[:,0], X[:,1], c=y, cmap='viridis', alpha=.7)\n",
    "plt.title(\"Random forest\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "Les figures ci-dessus montrent que la frontière de décision de l’arbre de décision est très irrégulière et présente de nombreux angles aigus suggérant un sur-apprentissage et une faible capacité à généraliser. Nous aurions du mal à faire des prévisions fiables sur les nouvelles données de test. En revanche, l'algorithme du bagging a une frontière plutôt lisse et ne présente aucun signe évident de sur-apprentissage.\n",
    "\n",
    "Examinons maintenant certains paramètres qui peuvent nous aider à augmenter la précision du modèle.\n",
    "\n",
    "## 3. Paramètres\n",
    "\n",
    "La [librairie scikit-learn](http://scikit-learn.org/stable/) implémente des forêts aléatoires en fournissant deux estimateurs : `RandomForestClassifier` et` RandomForestRegressor`.\n",
    "\n",
    "La liste complète des paramètres de forêt aléatoires pour la régression est présentée ci-dessous: "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "- `n_estimators` - le nombre d'arbres dans la forêt (par défaut = 10)\n",
    "- `criterion` - la fonction utilisée pour mesurer la qualité d'une division. Les critères pris en charge sont «mse» pour l'erreur quadratique moyenne, qui correspond à la réduction de la variance en tant que critère de sélection des caractéristiques, et «mae» pour l'erreur absolue moyenne (default = \"mse\").\n",
    "- `max_features` - le nombre de caractéristiques à prendre en compte lors de la recherche de la meilleure division. Vous pouvez spécifier le nombre ou le pourcentage de caractéristiques, ou choisir parmi les valeurs disponibles : \"auto\" (toutes les caractéristiques), \"sqrt\", \"log2\". (défaut = \"auto\")\n",
    "- `max_depth` - la profondeur maximale de l'arbre (par défaut, les nœuds sont développés jusqu'à ce que toutes les feuilles soient pures ou que toutes les feuilles contiennent moins de min_samples_split samples)\n",
    "- `min_samples_split` - nombre minimal d'échantillons requis pour fractionner un nœud interne. Peut être spécifié en nombre ou en pourcentage d'un nombre total d'échantillons (par défaut = 2)\n",
    "- `min_samples_leaf` - nombre minimal d'échantillons requis sur un noeud feuille (valeur par défaut = 1)\n",
    "- `min_weight_fraction_leaf` - fraction pondérée minimale de la somme totale des poids (de tous les échantillons en entrée) devant être au niveau d'un nœud feuille. Les échantillons ont un poids égal lorsque le poids de l'échantillon (sample_weight) n'est pas fourni (par défaut = 0)\n",
    "- `max_leaf_nodes` - le nombre maximal de feuilles (valeur par défaut = aucune restriction)\n",
    "- `min_impurity_split` - seuil d'arrêt précoce de la croissance des arbres. Un nœud se divisera si son impureté est supérieure au seuil, sinon c'est une feuille (par défaut = 1e-7)\n",
    "- `bootstrap` - si des exemples de bootstrap sont utilisés lors de la construction des arbres (valeur par défaut = True)\n",
    "- `oob_score` - indique s'il faut utiliser des échantillons out-of-bag pour estimer le R^2 sur des données invisibles (par défaut = False)\n",
    "- `n_jobs` - nombre de travaux à exécuter en parallèle, à la fois pour l'apprentissage et pour la prévision. Si -1, alors le nombre de travaux est défini sur le nombre de cœurs (par défaut = 1).\n",
    "- `random_state` - si int, random_state est le paramètre utilisé par le générateur de nombres aléatoires; si instance RandomState, random_state est le générateur de nombres aléatoires; si None, le générateur de nombres aléatoires est l'instance RandomState utilisée par np.random (par défaut = None)\n",
    "- `verbose` - contrôle la \"verbosité\" du processus de construction de l'arbre (valeur par défaut = 0)\n",
    "- `warm_start` - lorsqu'il est défini sur True, réutilise la solution de l'appel précédent pour ajuster et ajouter davantage d'estimateurs à l'ensemble. Sinon, ajustez simplement une nouvelle forêt (valeur par défaut = False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "En cas de classification, les paramètres sont généralement les mêmes. Seuls les éléments suivants diffèrent de `RandomForestClassifier` par rapport à `RandomForestRegressor`:\n",
    "\n",
    "   - `criterion` - la fonction utilisée pour mesurer la qualité d'une division. Les critères pris en charge sont \"gini\" pour l'impureté de Gini et \"entropy\" pour le gain d'information. Remarque: ce paramètre est spécifique à l’arbre (default = \"gini\") \n",
    "   - `class_weight` - le poids de chaque classe (par défaut, tous les poids égaux à 1, mais vous pouvez créer un dictionnaire avec des poids ou le spécifier comme équilibré \"balanced\" - utilise les valeurs des classes pour ajuster automatiquement les poids inversement proportionnels à la classe des fréquences dans les données d'entrée ou en tant que \"balanced_subsample\" - identique à \"balanced\" sauf que les poids sont calculés en fonction de l'échantillon bootstrap pour chaque arbre construit)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "Voici les paramètres auxquels nous devons prêter attention lorsque nous construisons un nouveau modèle :\n",
    "\n",
    "- `n_estimators` - le nombre d'arbres dans la forêt;\n",
    "- `criterion` - la fonction utilisée pour mesurer la qualité d'une division;\n",
    "- `max_features` - le nombre de caractéristiques à prendre en compte lors de la recherche de la meilleur partition;\n",
    "- `min_samples_leaf` - nombre minimal d'échantillons requis pour un nœud feuille;\n",
    "- `max_depth` - la profondeur maximale de l'arbre.\n",
    "\n",
    "<br>\n",
    "\n",
    "<div style=\"font-weight:700;font-size:15px\"> Appliquer les forêts aléatoires dans un problème réel </div>\n",
    "\n",
    " \n",
    "Dans cet exemple, nous examinerons la prévision du désabonnement des clients ou churn (taux d'attrition). C'est un problème de classification, nous allons donc utiliser la précision ou justesse (proportion de prédictions correctes) pour l'évaluation du modèle.\n",
    "\n",
    "Tout d’abord, construisons un classifieur simple que nous utiliserons comme base. Par souci de simplicité, nous n'utiliserons que des fonctions numériques."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "from sklearn.metrics import accuracy_score\n",
    "from sklearn.model_selection import (GridSearchCV, StratifiedKFold,\n",
    "                                     cross_val_score)\n",
    "\n",
    "# Load data\n",
    "df = pd.read_csv(\"../../data/telecom_churn.csv\")\n",
    "\n",
    "# Choose the numeric features\n",
    "cols = []\n",
    "for i in df.columns:\n",
    "    if (df[i].dtype == \"float64\") or (df[i].dtype == 'int64'):\n",
    "        cols.append(i)\n",
    "        \n",
    "# Divide the dataset into the input and target\n",
    "X, y = df[cols].copy(), np.asarray(df[\"Churn\"],dtype='int8')\n",
    "\n",
    "# Initialize a stratified split of our dataset for the validation process\n",
    "skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)\n",
    "\n",
    "# Initialize the classifier with the default parameters \n",
    "rfc = RandomForestClassifier(random_state=42, n_jobs=-1)\n",
    "\n",
    "# Train it on the training set\n",
    "results = cross_val_score(rfc, X, y, cv=skf)\n",
    "\n",
    "# Evaluate the accuracy on the test set\n",
    "print(\"CV accuracy score: {:.2f}%\".format(results.mean() * 100))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "Nous avons une précision égale à 91,18%. Maintenant, essayons d’améliorer ce résultat et examinons le comportement des courbes d’apprentissage lorsque nous modifions les paramètres de base.\n",
    "\n",
    "Commençons par le nombre d'arbres : "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Initialize the validation\n",
    "skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)\n",
    "\n",
    "# Create lists to save the values of accuracy on training and test sets\n",
    "train_acc = []\n",
    "test_acc = []\n",
    "temp_train_acc = []\n",
    "temp_test_acc = []\n",
    "trees_grid = [5, 10, 15, 20, 30, 50, 75, 100]\n",
    "\n",
    "for ntrees in trees_grid:\n",
    "    rfc = RandomForestClassifier(n_estimators=ntrees, random_state=42, n_jobs=-1)\n",
    "    temp_train_acc = []\n",
    "    temp_test_acc = []\n",
    "    for train_index, test_index in skf.split(X, y):\n",
    "        X_train, X_test = X.iloc[train_index], X.iloc[test_index]\n",
    "        y_train, y_test = y[train_index], y[test_index]\n",
    "        rfc.fit(X_train, y_train)\n",
    "        temp_train_acc.append(rfc.score(X_train, y_train))\n",
    "        temp_test_acc.append(rfc.score(X_test, y_test))\n",
    "    train_acc.append(temp_train_acc)\n",
    "    test_acc.append(temp_test_acc)\n",
    "    \n",
    "train_acc, test_acc = np.asarray(train_acc), np.asarray(test_acc)\n",
    "print(\"Best CV accuracy is {:.2f}% with {} trees\".format(max(test_acc.mean(axis=1))*100, \n",
    "                                                        trees_grid[np.argmax(test_acc.mean(axis=1))]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.style.use('ggplot')\n",
    "\n",
    "fig, ax = plt.subplots(figsize=(8, 4))\n",
    "ax.plot(trees_grid, train_acc.mean(axis=1), alpha=0.5, color='blue', label='train')\n",
    "ax.plot(trees_grid, test_acc.mean(axis=1), alpha=0.5, color='red', label='cv')\n",
    "ax.fill_between(trees_grid, test_acc.mean(axis=1) - test_acc.std(axis=1), \n",
    "                test_acc.mean(axis=1) + test_acc.std(axis=1), color='#888888', alpha=0.4)\n",
    "ax.fill_between(trees_grid, test_acc.mean(axis=1) - 2*test_acc.std(axis=1), \n",
    "                test_acc.mean(axis=1) + 2*test_acc.std(axis=1), color='#888888', alpha=0.2)\n",
    "ax.legend(loc='best')\n",
    "ax.set_ylim([0.88,1.02])\n",
    "ax.set_ylabel(\"Accuracy\")\n",
    "ax.set_xlabel(\"N_estimators\");"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "Comme vous pouvez le constater, lorsqu'un certain nombre d'arbres est atteint, notre précision sur l'ensemble de tests est très proche de l'asymptote. Vous pouvez décider vous-même quelle valeur serait le nombre optimal d'arbres pour votre problème.\n",
    "\n",
    "Les chiffres montrent également que nous avons atteint une précision de 100% sur l'ensemble des données d'entraînement, ce qui nous indique que nous sur-apprenons. Afin d'éviter le surapprentissage, nous devons ajouter des paramètres de régularisation à notre modèle.\n",
    "\n",
    "Commençons par la profondeur maximale des arbres `max_depth` et fixons le nombre d'arbres à 100 :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Create lists to save accuracy values on the training and test sets\n",
    "train_acc = []\n",
    "test_acc = []\n",
    "temp_train_acc = []\n",
    "temp_test_acc = []\n",
    "max_depth_grid = [3, 5, 7, 9, 11, 13, 15, 17, 20, 22, 24]\n",
    "\n",
    "for max_depth in max_depth_grid:\n",
    "    rfc = RandomForestClassifier(n_estimators=100, random_state=42, n_jobs=-1, max_depth=max_depth)\n",
    "    temp_train_acc = []\n",
    "    temp_test_acc = []\n",
    "    for train_index, test_index in skf.split(X, y):\n",
    "        X_train, X_test = X.iloc[train_index], X.iloc[test_index]\n",
    "        y_train, y_test = y[train_index], y[test_index]\n",
    "        rfc.fit(X_train, y_train)\n",
    "        temp_train_acc.append(rfc.score(X_train, y_train))\n",
    "        temp_test_acc.append(rfc.score(X_test, y_test))\n",
    "    train_acc.append(temp_train_acc)\n",
    "    test_acc.append(temp_test_acc)\n",
    "    \n",
    "train_acc, test_acc = np.asarray(train_acc), np.asarray(test_acc)\n",
    "print(\"Best CV accuracy is {:.2f}% with {} max_depth\".format(max(test_acc.mean(axis=1))*100, \n",
    "                                                        max_depth_grid[np.argmax(test_acc.mean(axis=1))]))\n",
    "\n",
    "fig, ax = plt.subplots(figsize=(8, 4))\n",
    "ax.plot(max_depth_grid, train_acc.mean(axis=1), alpha=0.5, color='blue', label='train')\n",
    "ax.plot(max_depth_grid, test_acc.mean(axis=1), alpha=0.5, color='red', label='cv')\n",
    "ax.fill_between(max_depth_grid, test_acc.mean(axis=1) - test_acc.std(axis=1), \n",
    "                test_acc.mean(axis=1) + test_acc.std(axis=1), color='#888888', alpha=0.4)\n",
    "ax.fill_between(max_depth_grid, test_acc.mean(axis=1) - 2*test_acc.std(axis=1), \n",
    "                test_acc.mean(axis=1) + 2*test_acc.std(axis=1), color='#888888', alpha=0.2)\n",
    "ax.legend(loc='best')\n",
    "ax.set_ylim([0.88,1.02])\n",
    "ax.set_ylabel(\"Accuracy\")\n",
    "ax.set_xlabel(\"Max_depth\");"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "Le paramètre `max_depth` se prête bien à la régularisation de notre modèle et ne surapprend pas aussi mal qu'auparavant. La précision du modèle a légèrement augmenté.\n",
    "\n",
    "Un autre paramètre important à ajuster est `min_samples_leaf`, qui contribue également à la régularisation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Create lists to save accuracy values on the training and test sets\n",
    "train_acc = []\n",
    "test_acc = []\n",
    "temp_train_acc = []\n",
    "temp_test_acc = []\n",
    "min_samples_leaf_grid = [1, 3, 5, 7, 9, 11, 13, 15, 17, 20, 22, 24]\n",
    "\n",
    "for min_samples_leaf in min_samples_leaf_grid:\n",
    "    rfc = RandomForestClassifier(n_estimators=100, random_state=42, n_jobs=-1, \n",
    "                                 min_samples_leaf=min_samples_leaf)\n",
    "    temp_train_acc = []\n",
    "    temp_test_acc = []\n",
    "    for train_index, test_index in skf.split(X, y):\n",
    "        X_train, X_test = X.iloc[train_index], X.iloc[test_index]\n",
    "        y_train, y_test = y[train_index], y[test_index]\n",
    "        rfc.fit(X_train, y_train)\n",
    "        temp_train_acc.append(rfc.score(X_train, y_train))\n",
    "        temp_test_acc.append(rfc.score(X_test, y_test))\n",
    "    train_acc.append(temp_train_acc)\n",
    "    test_acc.append(temp_test_acc)\n",
    "    \n",
    "train_acc, test_acc = np.asarray(train_acc), np.asarray(test_acc)\n",
    "print(\"Best CV accuracy is {:.2f}% with {} min_samples_leaf\".format(max(test_acc.mean(axis=1))*100, \n",
    "                                                        min_samples_leaf_grid[np.argmax(test_acc.mean(axis=1))]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fig, ax = plt.subplots(figsize=(8, 4))\n",
    "ax.plot(min_samples_leaf_grid, train_acc.mean(axis=1), alpha=0.5, color='blue', label='train')\n",
    "ax.plot(min_samples_leaf_grid, test_acc.mean(axis=1), alpha=0.5, color='red', label='cv')\n",
    "ax.fill_between(min_samples_leaf_grid, test_acc.mean(axis=1) - test_acc.std(axis=1), \n",
    "                test_acc.mean(axis=1) + test_acc.std(axis=1), color='#888888', alpha=0.4)\n",
    "ax.fill_between(min_samples_leaf_grid, test_acc.mean(axis=1) - 2*test_acc.std(axis=1), \n",
    "                test_acc.mean(axis=1) + 2*test_acc.std(axis=1), color='#888888', alpha=0.2)\n",
    "ax.legend(loc='best')\n",
    "ax.set_ylim([0.88,1.02])\n",
    "ax.set_ylabel(\"Accuracy\")\n",
    "ax.set_xlabel(\"Min_samples_leaf\");"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "Dans ce cas, nous ne constatons aucune amélioration de la précision du jeu de validation, mais nous réduisons considérablement le sur-apprentissage à 2% tout en maintenant la précision à environ 92%.\n",
    "\n",
    "Considérons le paramètre `max_features`. Pour la classification, la valeur $\\large \\sqrt{d}$ (nombre total de caractéristiques) est généralement utilisée comme choix par défaut. Voyons s'il serait optimal d'utiliser 4 caractéristiques dans notre cas :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Create lists to save accuracy values on the training and test sets\n",
    "train_acc = []\n",
    "test_acc = []\n",
    "temp_train_acc = []\n",
    "temp_test_acc = []\n",
    "max_features_grid = [2, 4, 6, 8, 10, 12, 14, 16]\n",
    "\n",
    "for max_features in max_features_grid:\n",
    "    rfc = RandomForestClassifier(n_estimators=100, random_state=42, n_jobs=-1, \n",
    "                                 max_features=max_features)\n",
    "    temp_train_acc = []\n",
    "    temp_test_acc = []\n",
    "    for train_index, test_index in skf.split(X, y):\n",
    "        X_train, X_test = X.iloc[train_index], X.iloc[test_index]\n",
    "        y_train, y_test = y[train_index], y[test_index]\n",
    "        rfc.fit(X_train, y_train)\n",
    "        temp_train_acc.append(rfc.score(X_train, y_train))\n",
    "        temp_test_acc.append(rfc.score(X_test, y_test))\n",
    "    train_acc.append(temp_train_acc)\n",
    "    test_acc.append(temp_test_acc)\n",
    "    \n",
    "train_acc, test_acc = np.asarray(train_acc), np.asarray(test_acc)\n",
    "print(\"Best CV accuracy is {:.2f}% with {} max_features\".format(max(test_acc.mean(axis=1))*100, \n",
    "                                                        max_features_grid[np.argmax(test_acc.mean(axis=1))]))\n",
    "\n",
    "fig, ax = plt.subplots(figsize=(8, 4))\n",
    "ax.plot(max_features_grid, train_acc.mean(axis=1), alpha=0.5, color='blue', label='train')\n",
    "ax.plot(max_features_grid, test_acc.mean(axis=1), alpha=0.5, color='red', label='cv')\n",
    "ax.fill_between(max_features_grid, test_acc.mean(axis=1) - test_acc.std(axis=1), \n",
    "                test_acc.mean(axis=1) + test_acc.std(axis=1), color='#888888', alpha=0.4)\n",
    "ax.fill_between(max_features_grid, test_acc.mean(axis=1) - 2*test_acc.std(axis=1), \n",
    "                test_acc.mean(axis=1) + 2*test_acc.std(axis=1), color='#888888', alpha=0.2)\n",
    "ax.legend(loc='best')\n",
    "ax.set_ylim([0.88,1.02])\n",
    "ax.set_ylabel(\"Accuracy\")\n",
    "ax.set_xlabel(\"Max_features\");"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "Dans notre cas, le nombre optimal de caractéristiques est égal à 10. Il s'agit de la valeur à laquelle le meilleur résultat est obtenu.\n",
    "\n",
    "Nous avons vu comment les courbes d'apprentissage évoluent avec différentes valeurs des paramètres de base. Maintenant, utilisons `GridSearch` pour trouver les paramètres optimaux pour notre exemple :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Initialize the set of parameters for exhaustive search and fit \n",
    "parameters = {'max_features': [4, 7, 10, 13], \n",
    "              'min_samples_leaf': [1, 3, 5, 7], \n",
    "              'max_depth': [5, 10, 15, 20]}\n",
    "rfc = RandomForestClassifier(n_estimators=100, random_state=42, n_jobs=-1)\n",
    "gcv = GridSearchCV(rfc, parameters, n_jobs=-1, cv=skf, verbose=1)\n",
    "gcv.fit(X, y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "gcv.best_params_, gcv.best_score_"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "## 4. Variance et dé-corrélation\n",
    "\n",
    "Écrivons la variance d'une forêt aléatoire comme\n",
    "\n",
    "$$\\large \\Var f(x) = \\rho(x)\\sigma^2(x)$$\n",
    "\n",
    "$$\\large \\rho(x) = \\Corr\\left[T(x_1,\\Theta_1(Z)),T(x_2,\\Theta_2(Z))\\right],$$\n",
    "\n",
    "où\n",
    "\n",
    "* $\\large \\rho(x)$ est le coefficient de corrélation de l'échantillon entre deux arbres utilisés pour calculer la moyenne\n",
    "* $\\large \\Theta_1(Z)$ et $\\large \\Theta_2(Z)$ sont une paire d'arbres sélectionnée de manière aléatoire sur des éléments de l'échantillon $Z$ sélectionnés de manière aléatoire;\n",
    "* $\\large T(x,\\Theta_i(Z))$ est la sortie du classifieur $\\large i$-th sur un vecteur d'entrée $\\large x$;\n",
    "* $\\large \\sigma^2(x)$ est la variance d'échantillon de tout arbre sélectionné au hasard :\n",
    "\n",
    "$$\\large \\sigma^2(x) = \\Var\\left[T(x,\\Theta(X))\\right]$$\n",
    "\n",
    "Il est facile de confondre $\\large \\rho(x)$ avec la corrélation moyenne entre les arbres entraînés dans une forêt aléatoire donnée lorsque nous considérons les arbres comme des N-vecteurs et calculons la corrélation par paire moyenne entre eux. Mais ce n'est pas le cas.\n",
    "\n",
    "En fait, cette corrélation conditionnelle n'est pas directement liée au processus d'établissement de la moyenne et la dépendance de $\\large \\rho(x)$ par rapport à $\\large x$ nous avertit de cette différence. $\\large \\rho(x)$ est la corrélation théorique entre une paire d'arbres aléatoires estimés sur l'entrée $\\large x$. Sa valeur provient de l'échantillonnage répété des données d'entraînement de la population $\\large Z$ et du choix aléatoire ultérieur d'une paire d'arbres. Dans le jargon statistique, il s'agit de la corrélation provoquée par la distribution d'échantillonnage de $\\large Z$ et $\\large \\Theta$.\n",
    "\n",
    "La covariance conditionnelle de toute paire d'arbres est égale à 0 car le bootstrapping et la sélection des caractéristiquess sont indépendants et répartis de manière identique.\n",
    "\n",
    "Si nous considérons la variance d'un seul arbre, cela dépend à peine des paramètres de la division ($\\large m$). Mais ils sont cruciaux pour les ensembles. La variance d'un arbre est beaucoup plus grande que celle d'un ensemble. Le livre *The Elements of Statistical Learning(Trevor Hastie, Robert Tibshirani и Jerome Friedman)* présente un excellent exemple de ce fait:\n",
    "\n",
    "![image](https://github.com/Yorko/mlcourse.ai/blob/master/img/variance_rf.png?raw=true)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "## 5. Biais\n",
    "\n",
    "Tout comme dans le bagging, le biais d'une forêt aléatoire est le même que celui d'un seul arbre $\\large T(x,\\Theta(Z))$:\n",
    "\n",
    "$$ \\large \\begin{array}{rcl} \\Bias &=& \\mu(x) - \\E_Z \\, f_{rf}(x) \\\\\n",
    "&=& \\mu(x) - \\E_Z \\, \\E_{\\Theta | Z} \\, T(x,\\Theta(Z))\\end{array}$$\n",
    "\n",
    "En valeur absolue, le biais est généralement plus élevé que celui d'un arbre non dépourvu car la randomisation et la réduction de l'espace d'échantillonnage imposent leurs propres restrictions au modèle. Par conséquent, les améliorations de la précision de prévision obtenues par le bagging et les forêts aléatoires sont uniquement le résultat de la réduction de la variance."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "## 6. Arbres extrêmement aléatoires\n",
    "\n",
    "Les arbres extrêmement aléatoires utilisent un plus grand degré de randomisation au niveau du choix du point de coupe (cut-point) lors de la division (partition) d'un nœud d'arbre. Comme dans les forêts aléatoires, un sous-ensemble aléatoire d'entités est utilisé. Mais, au lieu de rechercher les seuils optimaux, leurs valeurs sont sélectionnées de manière aléatoire pour chaque caractéristique possible, et le meilleur parmi ces seuils générés aléatoirement est utilisé comme meilleure règle pour scinder le nœud. Cela permet généralement de compenser une légère réduction de la variance du modèle par une légère augmentation du biais.\n",
    "\n",
    "Dans la bibliothèque `scikit-learn`, il existe 2 implémentations d'arbres extrêmement aléatoires: [ExtraTreesClassifier](http://scikit-learn.org/stable/modules/generated/sklearn.ensemble.ExtraTreesClassifier.html#sklearn.ensemble.ExtraTreesClassifier) et [ExtraTreesRegressor](http://scikit-learn.org/stable/modules/generated/sklearn.ensemble.ExtraTreesRegressor.html#sklearn.ensemble.ExtraTreesRegressor).\n",
    "\n",
    "Cette méthode doit être utilisée si vous avez considérablement sur-appris avec des forêts aléatoires ou un  gradient boosting."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "## 7. Similitudes entre Random Forest et les k plus proches voisins\n",
    "La méthode des forêts aléatoires (random forest) est similaire à la technique des voisins les plus proches. Les prévisions du random forest sont basées sur des étiquettes d’exemples identiques tirés de l’entraînement. Plus ces exemples apparaissent souvent dans la même feuille d’arbre, plus leur similarité est grande. Prouvons cela formellement.\n",
    "\n",
    "Considérons un problème de régression avec la fonction de perte quadratique. Soit $\\large T_n(x)$ le numéro de la feuille de l'arborescence $\\large n$-th dans une forêt aléatoire avec l'entrée $\\large x$.\n",
    "La réponse de l'algorithme pour le vecteur d'entrée $\\large x$ est égale à la réponse moyennée sur tous les exemples d'échantillon d'apprentissage qui entrent dans la feuille $\\large T_n(x)$. Cela peut être écrit comme\n",
    "\n",
    "$$\\large b_n(x) = \\sum_{i=1}^{l}w_n(x,x_i)y_i,$$\n",
    "\n",
    "où\n",
    "\n",
    "$$ \\large w_n(x, x_i) = \\frac{\\left[T_n(x) = T_n(x_i)\\right]}{\\sum_{j=1}^{l}\\left[T_n(x) = T_n(x_j)\\right]}$$\n",
    "\n",
    "Ensuite, la réponse de la composition est\n",
    "\n",
    "$$ \\large \\begin{array}{rcl} a_n(x) &=& \\frac{1}{N}\\sum_{n=1}^{N}\\sum_{i=1}^{l}w_n(x,x_i)y_i \\\\\n",
    "&=& \\sum_{i=1}^{l}\\left(\\frac{1}{N}\\sum_{j=1}^{N}w_n(x,x_j)\\right)y_i \\end{array}$$\n",
    "\n",
    "Vous pouvez voir que la réponse d'une forêt aléatoire est une somme pondérée de réponses sur tous les exemples d'entraînement.\n",
    "\n",
    "Il est également intéressant de noter que le numéro de la feuille $ \\large T_n(x)$, où l'instance $\\large x$ s'est terminée, est une caractéristique précieuse en soi. Par exemple, l’approche suivante fonctionne bien: \n",
    "1) Une composition d’un petit nombre d’arbres est formée sur un échantillon en utilisant une forêt aléatoire ou un gradient boosting. \n",
    "2) Les caractéristiques catégorielles $\\large T_1(x), \\dots, T_n(x)$ sont ajoutées à l'exemple.\n",
    "\n",
    "Ces nouvelles caractéritiques résultent de la division non linéaire de l'espace et fournissent des informations sur la similarité entre les exemples. Dans le livre *The Elements of Statistical Learning*, vous trouverez un bon exemple illustratif démontrant cette similitude entre les forêts aléatoires et la technique des k-plus proches voisins :\n",
    "\n",
    "\n",
    "![image](https://github.com/Yorko/mlcourse.ai/blob/master/img/knn_vs_rf.png?raw=true)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "## 8. Transformation d'un jeu de données en une représentation de grande dimension\n",
    "\n",
    "Les forêts aléatoires sont principalement utilisées dans l'apprentissage supervisé, mais il existe un moyen de les appliquer dans un environnement non supervisé.\n",
    "\n",
    "En utilisant la méthode `scikit-learn` [RandomTreesEmbedding](http://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomTreesEmbedding.html#sklearn.ensemble.RandomTreesEmbedding), nous pouvons transformer notre ensemble de données en une représentation de haute dimension (et \"éparse\"), [sparse](https://en.wikipedia.org/wiki/Sparse_matrix) representation. Nous construisons d’abord des arbres extrêmement aléatoires, puis utilisons l’index de la feuille contenant l’exemple en tant que nouvelle caractéristique.\n",
    "\n",
    "Par exemple, si l'entrée apparaît dans la première feuille, nous assignons $1$ comme valeur de caractéristique; sinon, on attribue $0$. C’est ce qu’on appelle un codage binaire (binary coding). Nous pouvons contrôler le nombre de caractéristiques et la rareté des données en augmentant ou en diminuant le nombre d'arbres et leur profondeur. Comme les points de données à proximité tombent probablement sur la même feuille, cette transformation fournit une estimation non paramétrique implicite de leur densité."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "lang": "fr"
   },
   "source": [
    "## 9. Avantages et inconvénients des forêts aléatoires\n",
    "\n",
    "<br>\n",
    "\n",
    "<div style=\"font-weight:700;font-size:20px\"> Avantages </div>\n",
    "\n",
    "<br>\n",
    "- Précision de prédiction élevée; fonctionnera mieux que les algorithmes linéaires dans la plupart des problèmes; la précision est comparable à celle du boosting.\n",
    "- Résistant aux valeurs aberrantes, grâce à un échantillonnage aléatoire.\n",
    "- Insensible à la mise à l'échelle des caractéristiques ainsi qu'à toute autre transformation monotone due à la sélection aléatoire de sous-espaces.\n",
    "- Ne nécessite pas de réglage fin des paramètres, fonctionne très bien tout de suite. Avec le réglage, il est possible d’obtenir un gain de précision de 0,5 à 3%, en fonction du réglage du problème et des données.\n",
    "- Efficace pour les jeux de données comportant un grand nombre de caractéristiques et de classes.\n",
    "- Traitent les variables continues et discrètes de manière égale.\n",
    "- Rarement en sur-apprentissage. En pratique, une augmentation du nombre d'arbres améliore presque toujours la composition. Mais, après avoir atteint un certain nombre d’arbres, la courbe d’apprentissage est très proche de l’asymptote.\n",
    "- Il existe des méthodes développées pour estimer l’importance des caractéristiques.\n",
    "- Fonctionne bien avec les données manquantes et maintient une bonne précision même lorsqu'une grande partie des données est manquante.\n",
    "- Permet de pondérer les classes sur l'ensemble du jeu de données ainsi que sur chaque échantillon d'arborescence.\n",
    "- Sous le capot, calcule les proximités entre des paires d'exemples qui peuvent ensuite être utilisés pour la mise en cluster, la détection de valeurs aberrantes ou des représentations de données intéressantes.\n",
    "- Les caractéristiques et propriétés ci-dessus peuvent être étendues aux données non étiquetées pour permettre la mise en cluster, la visualisation des données et la détection des valeurs aberrantes non supervisées.\n",
    "- Facilement parallélisable et hautement évolutif.\n",
    " \n",
    " \n",
    "<br>\n",
    "\n",
    "<div style=\"font-weight:700;font-size:20px\"> Inconvénients </div>\n",
    "\n",
    "<br>\n",
    " - En comparaison avec un arbre de décision unique, la sortie de Random Forest est plus difficile à interpréter.\n",
    " - Il n'y a pas de valeurs p formelles pour l'estimation de la signification des caractéristiques.\n",
    " - Résultats moins bons que les méthodes linéaires dans le cas de données éparses : saisie de texte, ... etc.\n",
    " - Contrairement à la régression linéaire, Random Forest ne peut pas extrapoler. Mais cela peut aussi être considéré comme un avantage car les valeurs aberrantes ne causent pas de valeurs extrêmes dans les forêts aléatoires.\n",
    " - Sujet à sur-apprentissage pour certains problèmes, en particulier lorsqu'il s'agit de données bruitées.\n",
    " - Dans le cas de variables catégorielles avec des nombres de niveaux différents, les forêts aléatoires favorisent les variables avec un plus grand nombre de niveaux. L'arbre conviendra davantage à une caractéristique à plusieurs niveaux car elle gagnera en précision.\n",
    " - Si un jeu de données contient des groupes de caractéristiques corrélées ayant une importance similaire pour les classes prédites, la préférence sera donnée aux groupes plus petits.\n",
    " - Le modèle résultant est volumineux et nécessite beaucoup de RAM."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": true,
    "lang": "fr"
   },
   "source": [
    "## 10. Mission de démonstration\n",
    "Vous pouvez vous entraîner avec cette [mission](https://www.kaggle.com/kashnitsky/a5-demo-logit-and-rf-for-credit-scoring) dans laquelle vous travaillerez avec la régression logistique et Random Forest dans un tâche de notation de crédit. Cette misison vous permet de vous exercer. Vous trouverez aussi une [solution](https://www.kaggle.com/kashnitsky/a5-demo-logit-and-rf-for-credit-scoring-sol).\n",
    "\n",
    "\n",
    "## 11. Ressources utiles\n",
    "- Main course [site](https://mlcourse.ai), [course repo](https://github.com/Yorko/mlcourse.ai), and YouTube [channel](https://www.youtube.com/watch?v=QKTuw4PNOsU&list=PLVlY_7IJCMJeRfZ68eVfEcu-UcN9BbwiX)\n",
    "- mlcourse.ai [lecture](https://www.youtube.com/watch?v=neXJL-AqI_c) on Random Forest\n",
    "- Medium [\"story\"](https://medium.com/open-machine-learning-course/open-machine-learning-course-topic-5-ensembles-of-algorithms-and-random-forest-8e05246cbba7) based on this notebook\n",
    "- Course materials as a [Kaggle Dataset](https://www.kaggle.com/kashnitsky/mlcourse)\n",
    "- If you read Russian: an [article](https://habrahabr.ru/company/ods/blog/324402/) on Habrahabr with ~ the same material. And a [lecture](https://youtu.be/G0DmuuFeC30) on YouTube\n",
    "- Chapter 15 of the book “[Elements of Statistical Learning](https://statweb.stanford.edu/~tibs/ElemStatLearn/)” by Jerome H. Friedman, Robert Tibshirani, and Trevor Hastie.\n",
    "- More about practical applications of random forests and other algorithms can be found in the [official documentation](http://scikit-learn.org/stable/modules/ensemble.html) of `scikit-learn`.\n",
    "- For a more in-depth discussion of variance and decorrelation of random forests, see the [original paper](https://www.stat.berkeley.edu/~breiman/randomforest2001.pdf)."
   ]
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "hide_input": false,
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.4"
  },
  "nbTranslate": {
   "displayLangs": [
    "*"
   ],
   "hotkey": "alt-t",
   "langInMainMenu": true,
   "sourceLang": "en",
   "targetLang": "fr",
   "useGoogleTranslate": true
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": false,
   "sideBar": true,
   "skip_h1_title": true,
   "title_cell": "Sommaire",
   "title_sidebar": "Contents",
   "toc_cell": true,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
